#include "rotation.hpp"

#include "qbe/src/ecs/app.hpp"

#include "qbe/src/ecs/query.hpp"

#include "qbe/src/axis/axis.hpp"
#include "qbe/src/input/input.hpp"
#include "qbe/src/select/select.hpp"
#include "qbe/src/state/state.hpp"
#include "qbe/src/undoRedo/undoRedo.hpp"
#include "qbe/src/utils/utils.hpp"

#include "qbe/src/layout/layout.hpp"

#include "qlib/all.h"

#include "../../../src/ql/common/myServiceEvent.h"

namespace qbe::rotation {

void clear_tag(ecs::Query query) {
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  auto view = reg.view<RotateTag>();
  view.each([&reg](entt::entity e) { reg.remove<RotateTag>(e); });
}

// 退出模式时回调
void exit_callback(ecs::Query query, state::AllModeType mode) {
  auto& move_param = query.get_resource<Models>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& state = query.get_resource<state::State>();

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  if (move_param.state == State::ManualRotation) {
    state.switchMode(move_param.selectMode);
  }

  clear_tag(query);
  move_param.reset();
}

void init(ecs::Commands commands, ecs::Query query) {
  Models models;
  commands.insert_resource(models);

  auto& state = query.get_resource<state::State>();
  state.addExitCall(state::EditingModeType::Rotation, exit_callback);
}

// 退出模式
void exit(ecs::Query query) {
  // 获取移动参数
  auto& move_param = query.get_resource<Models>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 退出模式
  auto& state = query.get_resource<state::State>();
  state.exit();

  if (move_param.state == State::ManualRotation) {
    state.switchMode(move_param.selectMode);
  }

  clear_tag(query);
  move_param.reset();
}

// 帧开始，模式转换
void stateTransformBegin(Models& models, state::State& state, input::HandleBundle* handle, ecs::Bus& bus, ecs::Query query) {
  if (models.state == State::AngleRotation) {
    models.waitManualRotaion = false;
    models.state = State::Wait;

    bus.send(qbe::UiMessage::OpenAngleRotationUi());
  }

  if (models.state == State::ManualRotation && handle->mousePressed(vsg::BUTTON_MASK_1)) {
    models.waitManualRotaion = true;
    models.state = State::Wait;

    auto& axisModule = query.get_resource<axis::Axis>();
    qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
    models.manual_center_pos = pos;

    bus.send(qbe::UiMessage::OpenManualRotationUi());

    {
      qbe::canvas::CanvasWidget* current_canvas;
      auto f = MyServiceEvent::getInstance()->useRegisterFunc<qbe::canvas::CanvasWidget*()>("DrawingBoardManager/currentCanvas");

      if (f) {
        current_canvas = f();
        current_canvas->setOperatorInfo("模式：旋转 | 请输入旋转角度");
      }
    }
  }

  if (models.state == State::Wait) {
    if (!models.waitManualRotaion) {
      auto angle_ok_rece = bus.receive<qbe::UiMessage::AngleRotationOk>();

      if (!angle_ok_rece.empty()) {
        models.self = angle_ok_rece.back().self;
        models.rotation = angle_ok_rece.back().rotation;

        models.execute = true;
        models.state = State::AngleRotation;
        return;
      }

      auto angle_can_rece = bus.receive<qbe::UiMessage::AngleRotationCancel>();

      if (!angle_can_rece.empty()) {
        models.state = State::Cancel;
        return;
      }

    } else {
      auto manual_ok_rece = bus.receive<qbe::UiMessage::ManualRotationOk>();

      if (!manual_ok_rece.empty()) {
        models.rotation = manual_ok_rece.back().rotation;

        models.execute = true;
        models.state = State::ManualRotation;
        return;
      }

      auto manual_can_rece = bus.receive<qbe::UiMessage::ManualRotationCancel>();

      if (!manual_can_rece.empty()) {
        models.state = State::ManualRotation;
        models.need_dele_esc_one = manual_can_rece.back().need_delete;
        return;
      }
    }
  }

  if (models.need_dele_esc_one && handle->keyReleased(vsg::KEY_Escape)) {
    models.need_dele_esc_one = false;
  } else if (models.state == State::ManualRotation && handle->keyReleased(vsg::KEY_Escape)) {
    models.state = State::None;

    state.switchMode(models.selectMode);
    state.exit();

    models.reset();
    clear_tag(query);
  }
}

// 帧尾-退出模式
void stateTransformEnd(State& state) {
  // 操作模式执行完就回退
  if (state == State::Cancel) {}
}

// 移动逻辑
void update(ecs::Query query, ecs::Bus& bus) {
  // 判断编辑模式为移动
  auto& state = query.get_resource<state::State>();

  if (state.getEditingMode() != state::EditingModeType::Rotation) {
    return;
  }

  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取输入 坐标系 撤销恢复
  auto& handModule = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axisModule = query.get_resource<axis::Axis>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();

  // 获取移动参数
  auto& models = query.get_resource<Models>();

  auto& selectModels = query.get_resource<select::OverallModel>();
  // selectModels.mouse_press = false;
  // selectModels.mouse_release = false;

  if (models.first) {
    auto view = reg.view<select::SelectTag>();
    view.each([&reg](entt::entity e) { reg.emplace_or_replace<RotateTag>(e); });

    if (models.state == State::ManualRotation) {
      models.selectMode = state.getSelectMode();
      auto& selectModels = query.get_resource<select::OverallModel>();
      // selectModels.mouse_press = false;
      // selectModels.mouse_release = false;
    }

    models.first = false;
  }

  stateTransformBegin(models, state, handModule, bus, query);

  if (models.state == State::Cancel) {
    clear_tag(query);
    models.reset();
    state.exit();
    return;
  }

  if (models.state == State::Clockwise90 || models.state == State::NoClockwise90) {
    auto view = reg.view<RotateTag>();

    double rotation = -M_PI / 2.0;
    if (models.state == State::NoClockwise90) {
      rotation *= -1;
    }

    bool onlyOneObj = true;
    entt::entity onlyOneEntity = entt::null;

    qlib::Vec2dArray box = utils::getInitBox();

    view.each([&reg, &rotation, &box, &onlyOneObj, &onlyOneEntity](entt::entity e) {
      if (onlyOneEntity != entt::null) {
        onlyOneObj = false;
      }

      auto box_t = utils::getBox(reg, e);
      box = utils::boxAndBox(box_t, box);

      onlyOneEntity = e;
    });

    if (onlyOneObj) {
      qlib::Reference::s_ptr* refer_ptr = reg.try_get<qlib::Reference::s_ptr>(onlyOneEntity);
      qlib::Label::s_ptr* label_ptr = reg.try_get<qlib::Label::s_ptr>(onlyOneEntity);
      qlib::Text::s_ptr* text_ptr = reg.try_get<qlib::Text::s_ptr>(onlyOneEntity);
      qlib::Fan::s_ptr* fan_ptr = reg.try_get<qlib::Fan::s_ptr>(onlyOneEntity);
      qlib::KeyPoint::s_ptr* key_ptr = reg.try_get<qlib::KeyPoint::s_ptr>(onlyOneEntity);

      if (refer_ptr) {
        undoRedoModule.start(cell);
        undoRedoModule.change(onlyOneEntity);
        (*refer_ptr)->rotation += rotation;

        auto box = (*refer_ptr)->bounding_box();
        auto center = (box[0] + box[1]) / 2.0;
        if ((*refer_ptr)->repetition.type != qlib::RepetitionType::None) {
          (*refer_ptr)->repetition.transform(1.0, false, rotation);
        }
        auto box_t = (*refer_ptr)->bounding_box();
        auto center_t = (box_t[0] + box_t[1]) / 2.0;

        auto vec = center - center_t;
        (*refer_ptr)->translate(vec.x, vec.y);

        layout_cmd.update(onlyOneEntity);
        undoRedoModule.end();
      } else if (label_ptr) {
        undoRedoModule.start(cell);
        undoRedoModule.change(onlyOneEntity);
        (*label_ptr)->rotation += rotation;
        layout_cmd.update(onlyOneEntity);
        undoRedoModule.end();
      } else if (text_ptr) {
        undoRedoModule.start(cell);
        undoRedoModule.change(onlyOneEntity);
        (*text_ptr)->rotation += rotation;
        layout_cmd.update(onlyOneEntity);
        undoRedoModule.end();
      } else if (fan_ptr) {
        undoRedoModule.start(cell);
        undoRedoModule.change(onlyOneEntity);
        (*fan_ptr)->rotation += rotation;
        layout_cmd.update(onlyOneEntity);
        undoRedoModule.end();
      } else if (key_ptr) {
        undoRedoModule.start(cell);
        undoRedoModule.change(onlyOneEntity);
        (*key_ptr)->rotation += rotation;
        layout_cmd.update(onlyOneEntity);
        undoRedoModule.end();
      } else {
        qlib::Vec2d center = (box[0] + box[1]) / 2.0;

        undoRedoModule.start(cell);
        view.each([&reg, &center, &rotation, &undoRedoModule, &layout_cmd](entt::entity e) {
          undoRedoModule.change(e);
          utils::rotation(reg, e, center, rotation);
          layout_cmd.update(e);
        });
        undoRedoModule.end();
      }
    } else {
      qlib::Vec2d center = (box[0] + box[1]) / 2.0;

      undoRedoModule.start(cell);
      view.each([&reg, &center, &rotation, &undoRedoModule, &layout_cmd](entt::entity e) {
        undoRedoModule.change(e);
        utils::rotation(reg, e, center, rotation);
        layout_cmd.update(e);
      });
      undoRedoModule.end();
    }

    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    models.reset();
    clear_tag(query);
    state.exit();
    return;
  }

  if (models.state == State::AngleRotation && models.execute) {
    if (!models.self) {
      auto view = reg.view<RotateTag>();
      double rotation = -models.rotation;

      qlib::Vec2dArray box = utils::getInitBox();
      view.each([&reg, &rotation, &box](entt::entity e) {
        auto box_t = utils::getBox(reg, e);
        box = utils::boxAndBox(box_t, box);
      });

      qlib::Vec2d center = (box[0] + box[1]) / 2.0;

      undoRedoModule.start(cell);
      view.each([&reg, &center, &rotation, &undoRedoModule, &layout_cmd](entt::entity e) {
        undoRedoModule.change(e);
        utils::rotation(reg, e, center, rotation);
        layout_cmd.update(e);
      });
      undoRedoModule.end();
    } else {
      auto view = reg.view<RotateTag>();
      double rotation = -models.rotation;

      undoRedoModule.start(cell);
      view.each([&reg, &rotation, &undoRedoModule, &layout_cmd](entt::entity e) {
        undoRedoModule.change(e);
        utils::rotation(reg, e, rotation);
        layout_cmd.update(e);
      });
      undoRedoModule.end();
    }

    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    models.reset();
    clear_tag(query);
    state.exit();
    return;
  }

  if (models.state == State::ManualRotation && models.state != State::Wait) {
    {
      qbe::canvas::CanvasWidget* current_canvas;
      auto f = MyServiceEvent::getInstance()->useRegisterFunc<qbe::canvas::CanvasWidget*()>("DrawingBoardManager/currentCanvas");

      if (f) {
        current_canvas = f();
        current_canvas->setOperatorInfo("模式：旋转 | 请选择旋转中心点");
      }
    }
  }

  if (models.state == State::ManualRotation && models.execute) {
    auto view = reg.view<RotateTag>();
    double rotation = models.rotation;

    // qlib::Vec2dArray box = utils::getInitBox();
    // view.each([&reg, &rotation, &box](entt::entity e) {
    //   auto box_t = utils::getBox(reg, e);
    //   box = utils::boxAndBox(box_t, box);
    // });

    qlib::Vec2d center = models.manual_center_pos;

    undoRedoModule.start(cell);
    view.each([&reg, &center, &rotation, &undoRedoModule, &layout_cmd](entt::entity e) {
      undoRedoModule.change(e);

      auto refer = reg.try_get<qlib::Reference::s_ptr>(e);
      if (refer) {
        auto refer_ptr = refer;

        auto box = (*refer_ptr)->bounding_box();
        auto center = (box[0] + box[1]) / 2.0;
        if ((*refer_ptr)->repetition.type != qlib::RepetitionType::None) {
          (*refer_ptr)->repetition.transform(1.0, false, rotation);
        }
        auto box_t = (*refer_ptr)->bounding_box();
        auto center_t = (box_t[0] + box_t[1]) / 2.0;

        auto vec = center - center_t;
        (*refer_ptr)->translate(vec.x, vec.y);
      }

      utils::rotation(reg, e, center, rotation);
      layout_cmd.update(e);
    });
    undoRedoModule.end();

    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    models.reset();
    clear_tag(query);
    state.switchMode(models.selectMode);
    state.exit();
    return;
  }

  stateTransformEnd(models.state);
}

void Plugin::build(ecs::App& app) {
  app.add_stage<InitStage>();
  app.add_stage<UpdateStage>();

  app.add_systems<InitStage>(init);
  app.add_systems<UpdateStage>(update);
}

}  // namespace qbe::rotation